package com.meida.module.user.provider.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.meida.common.constants.CommonConstants;
import com.meida.common.enums.AccountTypeEnum;
import com.meida.common.enums.StateEnum;
import com.meida.common.exception.OpenAlertException;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.mybatis.entity.EntityMap;
import com.meida.common.mybatis.model.PageModel;
import com.meida.common.mybatis.model.PageParams;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.mybatis.query.CriteriaUpdate;
import com.meida.common.utils.ApiAssert;
import com.meida.common.utils.FlymeUtils;
import com.meida.common.utils.StringUtils;
import com.meida.common.utils.WebUtils;
import com.meida.module.system.client.entity.BaseUserAccountLogs;
import com.meida.module.system.provider.mapper.BaseUserAccountLogsMapper;
import com.meida.module.user.client.constants.AppConstants;
import com.meida.module.user.client.dto.ThirdBindParams;
import com.meida.module.user.client.entity.AppAccount;
import com.meida.module.user.client.entity.AppUser;
import com.meida.module.user.provider.mapper.AppAccountMapper;
import com.meida.module.user.provider.service.AppAccountService;
import com.meida.module.user.provider.service.AppUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.Optional;

/**
 * @author zyf
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class AppAccountServiceImpl extends BaseServiceImpl<AppAccountMapper, AppAccount> implements AppAccountService {

    @Autowired
    private AppAccountMapper appAccountMapper;

    @Autowired
    private AppUserService appUserService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private BaseUserAccountLogsMapper baseUserAccountLogsMapper;


    /**
     * 注册账号
     *
     * @param username
     * @param avatar
     * @param accontType
     * @param nickName
     * @return
     */
    @Override
    public AppAccount register(String username, String avatar, String accontType, String nickName) {
        AppAccount baseUserAccount = getUserAccount(username, null);
        if (ObjectUtils.isEmpty(baseUserAccount)) {
            //加密
            String encodePassword = passwordEncoder.encode(AppConstants.DEF_PWD);
            baseUserAccount = new AppAccount(username, encodePassword, accontType, nickName, avatar);
            appAccountMapper.insert(baseUserAccount);
        }
        return baseUserAccount;
    }

    /**
     * 绑定账户
     */
    @Override
    public ResultBody thirdBind(Long userId, ThirdBindParams thirdBindParams) {
        CriteriaQuery cq = new CriteriaQuery(AppAccount.class);
        // AppAccount systemAccount = getOne(cq.eq(true, "account", thirdBindParams.getAccountName()));
        Boolean exist = isExist(userId, thirdBindParams.getAccountType().getCode());
        String message;
        if (!exist) {
            String encodePassword = passwordEncoder.encode(AppConstants.DEF_PWD);
            AppAccount systemAccount = new AppAccount(userId, thirdBindParams.getAccountName(), encodePassword, thirdBindParams.getAccountType().getCode(), thirdBindParams.getNickName(), thirdBindParams.getAvatar());
            save(systemAccount);
            message = "绑定成功";
        } else {
            QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
            queryWrapper.lambda()
                    .eq(AppAccount::getUserId, userId)
                    // .eq(AppAccount::getAccount, thirdBindParams.getAccountName())
                    .eq(AppAccount::getAccountType, thirdBindParams.getAccountType().getCode());
            int n = appAccountMapper.delete(queryWrapper);
            if (n > 0) {
                message = "解绑成功";
            } else {
                return ResultBody.failed("请使用绑定账户进行解绑");
            }
        }
        Boolean qq = isExist(userId, AccountTypeEnum.QQ.getCode());
        Boolean weibo = isExist(userId, AccountTypeEnum.WEIBO.getCode());
        Boolean weixin = isExist(userId, AccountTypeEnum.WEIXIN.getCode());
        EntityMap map = new EntityMap();
        map.put(AccountTypeEnum.WEIXIN.getCode(), weixin);
        map.put(AccountTypeEnum.QQ.getCode(), qq);
        map.put(AccountTypeEnum.WEIBO.getCode(), weibo);
        return ResultBody.ok(message, map);
    }

    /**
     * 注册账号
     *
     * @param accountName
     * @param password
     * @return
     */
    @Override
    public AppAccount registerByMobile(String accountName, String password) {
        String avatar = CommonConstants.DEFAULT_USERHEAD;
        String accontType = AccountTypeEnum.MOBILE.getCode();
        AppAccount baseUserAccount = getUserAccount(accountName, accontType);
        if (ObjectUtils.isEmpty(baseUserAccount)) {
            //加密
            String encodePassword = passwordEncoder.encode(password);
            baseUserAccount = new AppAccount(accountName, encodePassword, accontType, "", avatar);
            appAccountMapper.insert(baseUserAccount);
        }
        return baseUserAccount;
    }


    /**
     * 支持系统用户名、手机号、email登陆
     *
     * @param accountName
     * @return
     */
    @Override
    public AppAccount applogin(String accountName) {
        if (StringUtils.isBlank(accountName)) {
            return null;
        }
        Map<String, String> headers = WebUtils.getHttpHeaders(WebUtils.getHttpServletRequest());
        // 第三方登录标识
        String thirdParty = headers.get(AppConstants.HEADER_X_THIRDPARTY_LOGIN);
        QueryWrapper<AppAccount> qw = new QueryWrapper();
        qw.lambda().eq(AppAccount::getAccount, accountName);
        if (StringUtils.isNotBlank(thirdParty)) {
            //第三方登录加入登录类型,防止不同平台的三方账户重复
            qw.lambda().eq(AppAccount::getAccountType, thirdParty);
        }
        AppAccount account = appAccountMapper.selectOne(qw);
        if (FlymeUtils.isNotEmpty(account)) {
            Long userId = account.getUserId();
            if (FlymeUtils.isNotEmpty(userId)) {
                AppUser appUser = appUserService.getUserById(account.getUserId());
                if (appUser.getStatus().equals(StateEnum.DISABLE.getCode())) {
                    ApiAssert.failure("用户已禁用");
                }
                Long companyId = Optional.ofNullable(appUser.getCompanyId()).orElse(null);
                account.setCompanyId(companyId);
                //添加登录日志
                try {
                    HttpServletRequest request = WebUtils.getHttpServletRequest();
                    if (request != null) {
                        BaseUserAccountLogs log = new BaseUserAccountLogs();
                        log.setUserId(account.getUserId());
                        log.setAccount(account.getAccount());
                        log.setLoginTime(new Date());
                        log.setUserType(appUser.getUserType());
                        log.setAccountId(String.valueOf(account.getAccountId()));
                        log.setAccountType(account.getAccountType());
                        log.setLoginAgent(request.getHeader(HttpHeaders.USER_AGENT));
                        baseUserAccountLogsMapper.insert(log);
                    }
                } catch (Exception e) {
                    log.error("添加登录日志失败:{}", e);
                }
            }
        }


        return account;
    }


    /**
     * 注册系统用户名账户
     *
     * @param userId
     * @param accontName
     * @param password
     */
    @Override
    public AppAccount registerUsernameAccount(Long userId, String accontName, String password, Boolean check) {
        if (check) {
            ApiAssert.isFalse("账户已注册", isExist(accontName, AccountTypeEnum.USERNAME.getCode()));
        }
        String encodePassword = passwordEncoder.encode(Optional.ofNullable(password).orElse(CommonConstants.DEF_PWD));
        AppAccount baseUserAccount = new AppAccount(userId, accontName, encodePassword, AccountTypeEnum.USERNAME.getCode());
        appAccountMapper.insert(baseUserAccount);
        return baseUserAccount;
    }


    /**
     * 注册email账号
     *
     * @param userId
     * @param email
     * @param password
     */
    @Override
    public AppAccount registerEmailAccount(Long userId, String email, String password) {
        if (!StringUtils.matchEmail(email)) {
            return null;
        }
        if (isExist(email, AccountTypeEnum.EMAIL.getCode())) {
            //已经注册
            return null;
        }
        String encodePassword = passwordEncoder.encode(Optional.ofNullable(password).orElse(CommonConstants.DEF_PWD));
        AppAccount baseUserAccount = new AppAccount(userId, email, encodePassword, AccountTypeEnum.EMAIL.getCode());
        appAccountMapper.insert(baseUserAccount);
        return baseUserAccount;
    }


    /**
     * 注册手机账号
     *
     * @param userId
     * @param mobile
     * @param password
     */
    @Override
    public AppAccount registerMobileAccount(Long userId, String mobile, String password, Boolean check) {
        if (check) {
            ApiAssert.isTrue("手机号格式不正确", StringUtils.matchMobile(mobile));
            ApiAssert.isFalse("账户已注册", isExist(mobile, AccountTypeEnum.MOBILE.getCode()));
        }
        String encodePassword = passwordEncoder.encode(Optional.ofNullable(password).orElse(CommonConstants.DEF_PWD));
        AppAccount baseUserAccount = new AppAccount(userId, mobile, encodePassword, AccountTypeEnum.MOBILE.getCode());
        appAccountMapper.insert(baseUserAccount);
        return baseUserAccount;
    }


    /**
     * 根据旧密码重置用户密码
     *
     * @param userId
     * @param oldPassword
     * @param newPassword
     * @return
     */
    @Override
    public void resetPassword(Long userId, String oldPassword, String newPassword) {
        if (userId == null || StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword)) {
            return;
        }
        AppUser userProfile = appUserService.getUserById(userId);
        if (userProfile == null) {
            throw new OpenAlertException("用户信息不存在!");
        }
        if (CommonConstants.ROOT.equals(userProfile.getUserName())) {
            throw new OpenAlertException("默认用户不允许修改!");
        }
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(AppAccount::getAccount, userProfile.getUserName())
                .eq(AppAccount::getAccountType, AccountTypeEnum.USERNAME.getCode());
        AppAccount baseUserAccount = baseMapper.selectOne(queryWrapper);
        if (baseUserAccount == null) {
            return;
        }
        String oldPasswordEncoder = passwordEncoder.encode(oldPassword);
        if (!passwordEncoder.matches(baseUserAccount.getPassword(), oldPasswordEncoder)) {
            throw new OpenAlertException("原密码错误!");
        }
        baseUserAccount.setPassword(passwordEncoder.encode(newPassword));
        appAccountMapper.updateById(baseUserAccount);
    }


    @Override
    public void resetPwdBySmsCode(String mobile, String smsCode, String newPassword) {
        redisUtils.validSmsCode(mobile, smsCode);
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(AppAccount::getAccount, mobile);
        AppAccount appAccount = baseMapper.selectOne(queryWrapper);
        ApiAssert.isNotEmpty("账户不存在", appAccount);
        appAccount.setPassword(passwordEncoder.encode(newPassword));
        appAccountMapper.updateById(appAccount);
    }

    @Override
    public void resetPwdByOldPwd(Long accountId, String oldPassword, String newPassword) {
        AppAccount appAccount = getById(accountId);
        ApiAssert.isNotEmpty("账户不存在", appAccount);
        ApiAssert.isTrue("旧密码不正确", passwordEncoder.matches(oldPassword, appAccount.getPassword()));
        ApiAssert.isFalse("新旧密码不能相同", passwordEncoder.matches(oldPassword, passwordEncoder.encode(newPassword)));
        appAccount.setPassword(passwordEncoder.encode(newPassword));
        appAccountMapper.updateById(appAccount);
    }

    @Override
    public void resetPwd(Long userId, String pasword) {
        AppAccount appAccount = getMobileAccount(userId);
        String encodePassword = passwordEncoder.encode(Optional.ofNullable(pasword).orElse(CommonConstants.DEF_PWD));
        if (FlymeUtils.isNotEmpty(appAccount)) {
            appAccount.setPassword(encodePassword);
            CriteriaUpdate cu = new CriteriaUpdate();
            cu.set("password", encodePassword);
            cu.eq("accountId", appAccount.getAccountId());
            update(cu);
        }
        AppAccount userNameAccount = getUserNameAccount(userId);
        if (FlymeUtils.isNotEmpty(userNameAccount)) {
            CriteriaUpdate cu = new CriteriaUpdate();
            cu.set("password", encodePassword);
            cu.eq("accountId", userNameAccount.getAccountId());
            update(cu);
        }
    }


    /**
     * 检查是否已注册账号
     *
     * @param userId
     * @param account
     * @param accountType
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean isExist(Long userId, String account, String accountType) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(AppAccount::getAccount, account)
                .eq(AppAccount::getAccountType, accountType);
        int count = appAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean isExist(String account, String accountType) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getAccount, account)
                .eq(AppAccount::getAccountType, accountType);
        int count = appAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean isExist(Long userId, String accountType) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(AppAccount::getAccountType, accountType);
        int count = appAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean checkByAccountName(String accountName) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(true, AppAccount::getAccount, accountName);
        int count = appAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean accountIsBind(String accountName) {
        QueryWrapper<AppAccount> cq = new QueryWrapper();
        cq.lambda().eq(AppAccount::getAccount, accountName);
        AppAccount appAccount = appAccountMapper.selectOne(cq);
        if (ObjectUtil.isNull(appAccount)) {
            return false;
        }
        Long userId = appAccount.getUserId();
        if (FlymeUtils.isEmpty(userId)) {
            return false;
        }
        return true;
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public AppAccount getUserAccount(String account, String accountType) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getAccount, account)
                .eq(false, AppAccount::getAccountType, accountType);
        return appAccountMapper.selectOne(queryWrapper);

    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public AppAccount getUserNameAccount(Long userId) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(true, AppAccount::getAccountType, AccountTypeEnum.USERNAME);
        return appAccountMapper.selectOne(queryWrapper);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public AppAccount getMobileAccount(Long userId) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(true, AppAccount::getAccountType, AccountTypeEnum.MOBILE);
        return appAccountMapper.selectOne(queryWrapper);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public AppAccount getAccount(Long userId, String accountType) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(true, AppAccount::getAccountType, accountType);
        return appAccountMapper.selectOne(queryWrapper);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public AppAccount getMobileAccount(String mobile) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getAccount, mobile)
                .eq(true, AppAccount::getAccountType, AccountTypeEnum.MOBILE);
        return appAccountMapper.selectOne(queryWrapper);
    }


    /**
     * 解绑email账号
     *
     * @param userId
     * @param email
     * @return
     */
    @Override
    public void removeEmailAccount(Long userId, String email) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(AppAccount::getAccount, email)
                .eq(AppAccount::getAccountType, AccountTypeEnum.EMAIL.getCode());
        appAccountMapper.delete(queryWrapper);
    }

    /**
     * 解绑手机账号
     *
     * @param userId
     * @param mobile
     * @return
     */
    @Override
    public void removeMobileAccount(Long userId, String mobile) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(AppAccount::getUserId, userId)
                .eq(AppAccount::getAccount, mobile)
                .eq(AppAccount::getAccountType, AccountTypeEnum.MOBILE.getCode());
        appAccountMapper.delete(queryWrapper);
    }

    /**
     * 删除账户
     *
     * @param userIds
     * @return
     */
    @Override
    public void removeAccount(Long[] userIds) {
        QueryWrapper<AppAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .in(AppAccount::getUserId, userIds);
        appAccountMapper.delete(queryWrapper);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody pageList(PageModel model) {
        CriteriaQuery<EntityMap> cq = new CriteriaQuery(model, AppUser.class);
        PageParams pageParams = cq.getPageParams();
        AppAccount query = cq.getEntity(AppAccount.class);
        cq.eq(true, "userId", query.getUserId());
        return basePageList(cq);
    }
}
